//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef __ELASTOS_HAT_H__
#define __ELASTOS_HAT_H__

#include <ddk/allocpage.h>

#define STACK_GROW_MAX_SIZE     64

extern Address g_ASIDManage[];

class HAT
{
public:
    void Activate();

    bool_t LoadMap(
        uint_t vBase, uint_t vLimit, uint_t pBase,
        dword_t dwProtect, Boolean bIsFlushCache);

    void UnloadMap(uint_t vBase, uint_t vLimit);

    bool_t SetProtect(uint_t vBase, uint_t vLimit, dword_t dwProtect);

    void Dispose();

    HAT();
    ~HAT();

    void SyncGlobalHAT();

private:
    PageDirEntry  *m_pPageDir;
    uint32_t  m_uASID;

public:
    static inline HAT * GetCurrent();

    static void ActivateKHAT();

    static bool_t LoadKernelMap(
        uint_t vBase, uint_t vLimit, uint_t pBase, dword_t dwProtect);

    static void UnloadKernelMap(uint_t vBase, uint_t vLimit);
};

inline void HAT::Activate()
{
    if (this == GetCurrent()) return;

    SetPageDirAddress(m_uASID);

#ifdef _DEBUG
    uint32_t    uEntryHi;
#ifdef _GNUC
    ASM("mfc0   %0, $10;":"=r&"(uEntryHi));
#elif defined(_EVC)
    ASM(
        "mfc0   $12, $10;"
        "sw     $12, 0(%0);", &uEntryHi);
#else
#error unknown compiler
#endif
    assert(m_uASID == uEntryHi);
#endif
}

inline HAT * HAT::GetCurrent()
{
    uint32_t uEntryHiASID;

#if defined(_GNUC)
    ASM("mfc0 %0, $10;":"=r&"(uEntryHiASID)); // read the EntryHi
#elif defined(_EVC)
    ASM(
        "mfc0   t3, $10;"
        "sw     t3, 0(%0);", &uEntryHiASID);
#else
#error unknown compiler
#endif

    uEntryHiASID = uEntryHiASID & 0xff;

    return (HAT *)g_ASIDManage[uEntryHiASID];
}

#endif // __ELASTOS_HAT_H__
